#pragma once

#include "CTableCache.h"
#include "mysql/MysqlDatabase.h"
#include "Debugger.h"

template <typename T>
class CMysqlTableCache : public CTableCache<T>
{
public:
	CMysqlTableCache() {}
	virtual ~CMysqlTableCache() {}

	virtual ITableCache* New() const {
		return new CMysqlTableCache<T>();
	}

	virtual bool LoadData() {
		DBGASSERT(m_pDB != NULL);
		auto conn = m_pDB->GetConnAutoPtr();
		if (!conn) {
			WLOG("load mysql table cache `%s`, but connect database failed.",
				GetTableName<T>());
			return false;
		}

		auto rst = conn->QueryFormat("SELECT * FROM `%s`", GetTableName<T>());
		if (!rst) {
			WLOG("load mysql table cache `%s`, but query database failed.",
				GetTableName<T>());
			return false;
		}

		const size_t columns = GetTableFieldNumber<T>();
		if (rst.GetFieldCount() != columns) {
			WLOG("load mysql table cache `%s`, but field number is't match.",
				GetTableName<T>());
			return false;
		}

		const size_t rows = rst.GetRowCount();
		if (rows > 0) {
			if (this->m_hasIndex) {
				this->m_mapTable.reserve(rows);
			} else {
				this->m_table.reserve(rows);
			}
			while (rst.NextRow()) {
				MysqlRow row = rst.Fetch();
				T entity;
				for (size_t index = 0; index < columns; ++index, row.Next()) {
					SetTableFieldValue(
						entity, index, {row.GetString(), row.GetLength()});
				}
				if (this->m_hasIndex) {
					auto key = GetTableKeyValue<T>(entity);
					this->m_mapTable[key] = std::move(entity);
				} else {
					this->m_table.push_back(std::move(entity));
				}
			}
		}

		return true;
	}

	static void SetDB(MysqlDatabase* pDB) {
		DBGASSERT(m_pDB == NULL);
		m_pDB = pDB;
	}

private:
	static MysqlDatabase* m_pDB;
};

template<class T>
MysqlDatabase* CMysqlTableCache<T>::m_pDB = NULL;
